import json
from sqlalchemy.ext.declarative import DeclarativeMeta
from datetime import datetime, date
from flask import request
from flask import make_response

DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
DATE_FORMAT = '%Y-%m-%d'
TIME_FORMAT = '%H:%M:%S'


def format_datetime(dt):
    if dt is None or dt == '':
        return ''
    return dt.strftime(DATETIME_FORMAT)


def format_date(d):
    if d is None or d == '':
        return ''
    return d.strftime(DATE_FORMAT)


def get_params():
    if request.args:
        return request.args
    if request.json:
        return request.json
    if request.form:
        return request.form


def json_response(data, msg='Success', code=200):
    resp_data = {
        'code': code,
        'msg': msg,
        'data': data
    }
    json_str = json.dumps(resp_data)
    resp = make_response(json_str)
    resp.headers['Content-Type'] = 'application/json'
    return resp


def new_alchemy_encoder():
    _visited_obj_s = []

    class AlchemyEncoder(json.JSONEncoder):
        def default(self, obj):
            if isinstance(obj.__class__, DeclarativeMeta):
                # don't re-visit self
                if obj in _visited_obj_s:
                    return None
                    _visited_obj_s.append(obj)

                # an SQLAlchemy class
                fields = {}
                for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
                    data = obj.__getattribute__(field)
                    try:
                        if isinstance(data, datetime):
                            data = data.strftime(DATETIME_FORMAT)
                        if isinstance(data, date):
                            data = data.strftime(DATE_FORMAT)
                        json.dumps(data)
                        fields[field] = data
                    except TypeError:
                        fields[field] = None
                return fields

            return json.JSONEncoder.default(self, obj)

    return AlchemyEncoder


def to_dumps(_list):
    if _list:
        return json.dumps(_list, cls=new_alchemy_encoder(), check_circular=False)
    else:
        return ''


class ApiException(Exception):
    status_code = 400

    def __init__(self, msg, code=None, data=None):
        self.msg = msg
        if code is not None:
            self.code = code
        self.data = data
